﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using UtilZ.Dotnet.Ex.ZLog;

namespace UtilZ.Dotnet.Ex.TTLV
{
    /// <summary>
    /// 
    /// </summary>
    public class TTLVDemo
    {
        /// <summary>
        /// 测试
        /// </summary>
        public static void Test()
        {
            try
            {

                //List<string> strList = new List<string>();
                //strList.Add("abc");
                //strList.Add(null);
                //strList.Add(string.Empty);
                //strList.Add("");
                //strList.Add("end");

                //string[] strArr = new string[] { "ycq", null, string.Empty, "zhn" };

                //string str = null;
                //object obj = str;
                //string str2 = Convert.ToString(obj);
                //var valueBuffer = System.Text.Encoding.UTF8.GetBytes(str2);

                TestNullField();

                TestGeneric();

                TestClass();

                TestStruct();


            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }

        private static void TestNullField()
        {
            try
            {
                var stu1 = new Stu() { Addr = "四川", ID = 24, Age = null };
                byte[] buffer1 = TTLVHelper.Encoding(stu1);
                var ret1 = TTLVHelper.Decoding<Stu>(buffer1);


                var stu2 = new Stu() { Addr = "四川2xvzxcv", ID = 22, Age = 18 };
                byte[] buffer2 = TTLVHelper.Encoding(stu2);
                var ret2 = TTLVHelper.Decoding<Stu>(buffer2);
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }

        private static void TestGeneric()
        {
            try
            {
                var cmd1 = new CommandBaseT<Stu>(222, new Stu() { Addr = "四川", ID = 24 });
                cmd1.Data = System.Text.Encoding.UTF8.GetBytes("hello word!三大一..");
                //cmd1.Data = null;
                byte[] buffer = cmd1.GenerateCommandData();

                var cmd2 = new CommandBaseT<Stu>();
                cmd2.Parse(buffer);
                string str = System.Text.Encoding.UTF8.GetString(cmd2.Data);
            }
            catch (Exception ex)
            {
                ZLoger.Error(ex);
            }
        }

        private static void TestClass()
        {

            var demo = new TTLVDemoObject();
            demo.PortList = new List<int>() { 1, 2, 3, 4, 5, 6 };
            demo.StringList = new List<string>() { "ycq", "yf" };
            demo.TimeList = new List<DateTime>() { DateTime.Parse("2019-03-25 18:00:00"), DateTime.Parse("2019-03-26 19:11:22") };
            demo.LongList = new List<long>() { 345345, 65786578, 675897689 };
            demo.ByteList = new List<byte>() { 1, 2, 3 };
            demo.ShortList = new List<short>() { 321, 654 };
            demo.CharList = new List<char>() { 'Z', 'Q', 'E' };
            demo.DoubleList = new List<double>() { 222.333d, 5555.678d };
            demo.SingleList = new List<float>() { 123.123f, 456.456f };
            demo.Sex = Sex.Z;
            demo.Sex2 = 123.123f;
            demo.Sex3 = 456.456453635d;
            demo.Sex4 = 345342564236543256;
            demo.Name = "白起";
            demo.Age = 31;
            demo.Person = new Person() { Addr = "天由", Leve = 23 };
            demo.Person.Pre = new Person { Addr = "Pre未名天", Leve = 99 };
            demo.Person.Next = new Person { Addr = "Next情怡", Leve = 22 };
            demo.Person.Next.Next = new Person { Addr = "Next222情怡", Leve = 32 };
            demo.Stu = new Stu() { Addr = "四川", ID = 24 };
            demo.City = "成都";
            demo.PersonList = new List<Person>();
            demo.PersonList.Add(new Person() { Addr = "文莉1", Leve = 24 });
            demo.PersonList.Add(new Person() { Addr = "文莉2", Leve = 25 });
            demo.PersonList.Add(new Person() { Addr = "文莉3", Leve = 26 });

            demo.PersonArr = new Person[1] { new Person() { Addr = "文网页版3", Leve = 36 } };
            demo.Stu2 = new Stu() { Addr = "成都", ID = 33 };

            var buffer = TTLVHelper.Encoding(demo);

            var result1 = TTLVHelper.Decoding<TTLVDemoObject>(buffer);

            var result2 = new TTLVDemoObject();
            TTLVHelper.Decoding(result2, buffer);


            using (var ms = new MemoryStream(buffer))
            {
                var result3 = TTLVHelper.Decoding<TTLVDemoObject>(ms, 0, ms.Length);


                var result4 = new TTLVDemoObject();
                ms.Position = 0;
                TTLVHelper.Decoding(result4, ms);
            }
        }

        private static void TestStruct()
        {
            var strx = new TTLVDemoStruct();
            strx.PortList = new List<int>() { 1, 2, 3, 4, 5, 6 };
            strx.Sex = Sex.Z;
            strx.Sex2 = 123.123f;
            strx.Sex3 = 456.456453635d;
            strx.Sex4 = 345342564236543256;
            strx.Name = "白起";
            strx.Age = 31;
            strx.Person = new Person() { Addr = "天由", Leve = 23 };
            strx.Age22 = 345;


            var buffer = TTLVHelper.Encoding(strx);

            var result1 = TTLVHelper.Decoding<TTLVDemoStruct>(buffer);

            ////var result2 = new TTLVDemoStruct();
            ////Decoding(buffer, ref result2);



            using (var ms = new MemoryStream(buffer))
            {
                var result3 = TTLVHelper.Decoding<TTLVDemoStruct>(ms);


                //    //var result4 = new TTLVDemoStruct();
                //    //ms.Position = 0;
                //    //Decoding(ms, ref result4);
            }
        }
    }


    internal struct TTLVDemoStruct
    {
        [TTLVAttribute(70, typeof(TTLVPrimitiveCollectionConverter))]
        public List<int> PortList { get; set; }

        [TTLVAttribute(50)]
        public Sex Sex { get; set; }

        [TTLVAttribute(51)]
        public float Sex2 { get; set; }

        [TTLVAttribute(52)]
        public double Sex3 { get; set; }

        [TTLVAttribute(53)]
        public long Sex4 { get; set; }

        [TTLVAttribute(5)]
        public string Name { get; set; }

        [TTLVAttribute(6)]
        public int Age { get; set; }

        [TTLVAttribute(7)]
        public Person Person { get; set; }

        [TTLVAttribute(8)]
        public int Age22;
    }

    internal class TTLVDemoObject
    {
        [TTLVAttribute(70, typeof(TTLVPrimitiveCollectionConverter))]
        public List<int> PortList { get; set; }

        [TTLVAttribute(72, typeof(TTLVPrimitiveCollectionConverter))]
        public List<string> StringList { get; set; }

        [TTLVAttribute(73, typeof(TTLVPrimitiveCollectionConverter))]
        public List<DateTime> TimeList { get; set; }

        [TTLVAttribute(74, typeof(TTLVPrimitiveCollectionConverter))]
        public List<long> LongList { get; set; }

        [TTLVAttribute(75, typeof(TTLVPrimitiveCollectionConverter))]
        public List<byte> ByteList { get; set; }

        [TTLVAttribute(76, typeof(TTLVPrimitiveCollectionConverter))]
        public List<short> ShortList { get; set; }

        [TTLVAttribute(77, typeof(TTLVPrimitiveCollectionConverter))]
        public List<char> CharList { get; set; }

        [TTLVAttribute(78, typeof(TTLVPrimitiveCollectionConverter))]
        public List<double> DoubleList { get; set; }

        [TTLVAttribute(79, typeof(TTLVPrimitiveCollectionConverter))]
        public List<Single> SingleList { get; set; }


        [TTLVAttribute(50)]
        public Sex Sex { get; set; }

        [TTLVAttribute(51)]
        public float Sex2;

        [TTLVAttribute(52)]
        public double Sex3;

        [TTLVAttribute(53)]
        public long Sex4;

        [TTLVAttribute(5)]
        public string Name { get; set; }

        [TTLVAttribute(6)]
        public int Age { get; set; }

        [TTLVAttribute(7)]
        public Person Person { get; set; }

        [TTLVAttribute(8, typeof(StuTTLVConvter))]
        public Stu Stu { get; set; }

        public string City { get; set; }


        [TTLVAttribute(9, false)]
        public List<Person> PersonList { get; set; }


        [TTLVAttribute(10, false)]
        public Person[] PersonArr { get; set; }

        [TTLVAttribute(11, typeof(TTLVSerializeConverter), null, TTLVSerializeType.Bin)]
        public Stu Stu2 { get; set; }

        public TTLVDemoObject()
        {

        }
    }

    internal enum Sex : byte
    {
        F = 1,

        M = 2,

        Z = 3
    }

    internal class Person
    {
        [TTLVAttribute(3)]
        public int Leve { get; set; }

        [TTLVAttribute(4)]
        public string Addr { get; set; }

        [TTLVAttribute(114)]
        public Person Next { get; set; }

        [TTLVAttribute(115)]
        public Person Pre { get; set; }
    }


    [Serializable]
    internal class Stu
    {
        [TTLVAttribute(1)]
        public long ID { get; set; }

        [TTLVAttribute(2)]
        public int? Age { get; set; }

        [TTLVAttribute(3)]
        public string Addr { get; set; }

        public Stu()
        {

        }
    }

    internal class StuTTLVConvter : TTLVConverterBase
    {
        public StuTTLVConvter()
            : base()
        {

        }

        /// <summary>
        /// 目标对象转换为bytes
        /// </summary>
        /// <param name="tag">标签</param>
        /// <param name="obj">转换对象</param>
        /// <param name="targetType">目标属性或字段类型</param>
        /// <param name="converterPara">转换器参数</param>
        /// <returns>转换结果</returns>
        public override byte[] ConvertToBytes(int tag, object obj, Type targetType, object converterPara)
        {
            var stu = (Stu)obj;
            byte[] content = System.Text.Encoding.UTF8.GetBytes(stu.Addr);
            byte[] level = BitConverter.GetBytes(stu.ID);
            byte[] buffer = new byte[level.Length + content.Length];
            Buffer.BlockCopy(level, 0, buffer, 0, level.Length);
            Buffer.BlockCopy(content, 0, buffer, level.Length, content.Length);
            return buffer;
        }

        /// <summary>
        /// 转换bytes到目标对象
        /// </summary>
        /// <param name="tag">标签</param>
        /// <param name="buffer">byte[]</param>
        /// <param name="memberValue">目标属性或字段值</param>
        /// <param name="targetType">目标属性或字段类型</param>
        /// <param name="converterPara">转换器参数</param>
        /// <returns>解析结果对象</returns>
        public override object ConvertBackObject(int tag, byte[] buffer, object memberValue, Type targetType, object converterPara)
        {
            Stu stu = (Stu)memberValue;
            if (stu == null)
            {
                stu = new Stu();
            }

            stu.ID = BitConverter.ToInt32(buffer, 0);
            stu.Addr = System.Text.Encoding.UTF8.GetString(buffer, 4, buffer.Length - 4);
            return stu;
        }
    }




    /// <summary>
    /// 命令基类[TTLV_Tag范围(0-100)]
    /// </summary>
    [Serializable]
    internal abstract class CommandBase
    {
        public CommandBase()
        {

        }

        public CommandBase(Int32 cmd)
        {
            this.Cmd = cmd;
        }

        /// <summary>
        /// 命令字
        /// </summary>
        [TTLVAttribute(1)]
        public Int32 Cmd { get; protected set; }

        /// <summary>
        /// 生成命令数据
        /// </summary>
        /// <returns>命令数据</returns>
        public byte[] GenerateCommandData()
        {
            return TTLVHelper.Encoding(this);
        }

        /// <summary>
        /// 解析命令数据
        /// </summary>
        /// <param name="data">传输命令</param>
        public void Parse(byte[] data)
        {
            TTLVHelper.Decoding(this, data);
        }
    }

    /// <summary>
    /// 泛型命令基类
    /// </summary>
    [Serializable]
    internal class CommandBaseT<T> : CommandBase
    {
        [TTLVAttribute(101)]
        public T Value { get; set; }

        [TTLVAttribute(102, typeof(TTLVPrimitiveCollectionConverter))]
        public byte[] Data { get; set; }

        public CommandBaseT()
        {

        }

        public CommandBaseT(Int32 cmd, T value)
        {
            this.Cmd = cmd;
            this.Value = value;
        }
    }


}
